package com.cy.wenxinapi.controller;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.cy.wenxinapi.ChatPromptRequest;
import com.cy.wenxinapi.service.impl.InterviewRecodeServiceImpl;
import com.cy.wenxinapi.util.QA;
import com.cy.wenxinapi.util.R;
import com.gearwenxin.client.PromptBotClient;
import com.gearwenxin.client.ernie.ErnieBot4Client;
import com.gearwenxin.client.stable.StableDiffusionXLClient;
import com.gearwenxin.common.Constant;
import com.gearwenxin.common.ConvertUtils;
import com.gearwenxin.common.ErrorCode;
import com.gearwenxin.core.ChatCore;
import com.gearwenxin.entity.enums.SamplerType;
import com.gearwenxin.entity.request.ImageBaseRequest;
import com.gearwenxin.entity.request.PromptRequest;
import com.gearwenxin.entity.response.ChatResponse;
import com.gearwenxin.entity.response.ImageResponse;
import com.gearwenxin.entity.response.PromptResponse;
import com.gearwenxin.exception.WenXinException;
import jakarta.annotation.Resource;
import org.springframework.http.MediaType;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import reactor.core.CoreSubscriber;
import reactor.core.publisher.Mono;

import java.io.IOException;
import java.sql.Struct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

/**
 * @author: c
 * @date: 2024/2/24 15:20
 * @description:
 */


@RestController
public class ChatController {

    // 要调用的模型的客户端（示例为文心4.0）
    @Resource
    private ErnieBot4Client ernieBot4Client;

    @Resource
    private PromptBotClient promptBotClient;
    @Resource
    private StableDiffusionXLClient stableDiffusionXLClient;

    /**
     * 微信小程序专用接口
     */

    @GetMapping("/chat_wx")
    public Mono<ChatResponse> chat_wx(String msg) {
        if (StrUtil.isNotEmpty(msg)) {
            return Mono.just(new ChatResponse("1", "1", "1", 1, 1, true, true, "1", null, "你的男朋友不在线", null, null, null, null, null, null, null, null)); // 示例返回一个带有默认提示信息的ChatResponse实例

        }

        if (msg.equals("1")) {
            return Mono.just(new ChatResponse("1", "1", "1", 1, 1, true, true, "1", null, "你的男朋友不在线", null, null, null, null, null, null, null, null)); // 示例返回一个带有默认提示信息的ChatResponse实例
        }


        if (StrUtil.isNotEmpty(msg)) {

            Mono<ChatResponse> chatResponseMono = ernieBot4Client.chatSingle( msg );

            return chatResponseMono;


        } else {
            return null;
        }
    }


    // 单次对话
    @GetMapping("/chat")
    public R  chatSingle(String msg) {

//        if (msg.equals("1")) {
//            return Mono.just(new ChatResponse("1", "1", "1", 1, 1, true, true, "1", null, "君不见，黄河之水天上来，奔流到海不复回。\n" +
//                    "\n" +
//                    "君不见，高堂明镜悲白发，朝如青丝暮成雪。\n" +
//                    "\n" +
//
//                    "古来圣贤皆寂寞，惟有饮者留其名。\n" +
//                    "\n" +
//                    "陈王昔时宴平乐，斗酒十千恣欢谑。\n" +
//                    "\n" +
//                    "主人何为言少钱，径须沽取对君酌。\n" +
//                    "\n" +
//                    "五花马，千金裘，呼儿将出换美酒，与尔同销万古愁。", null, null, null, null, null, null, null, null)); // 示例返回一个带有默认提示信息的ChatResponse实例
//
//        }


        if (StrUtil.isNotEmpty(msg)) {
            String promptBefore = "这是我进行模拟面试的记录，请根据回答情况进行评价，";

            String promptAfter = ",首先给出总分（满分100），然后每道题目分别给出评价和建议的回答。你回答的方式使用json格式，方便我提前评价内容，参考回答案例： {\n" +
                    "  \"total_score\": 80,\n" +
                    "  \"question_1\": {\n" +
                    "    \"score\": 90,\n" +
                    "    \"evaluation\": \"xxx\",\n" +
                    "    \"suggested_answer\": \" xxx\"\n" +
                    "  },...";
            Mono<ChatResponse> chatResponseMono = ernieBot4Client.chatSingle(promptBefore + msg + promptAfter);
            System.out.println(chatResponseMono);

            ChatResponse block = chatResponseMono.block();
            String result = block.getResult();
            String replace = result.replace("```json", "").replace("```", "");
            JSONObject jsonObject = JSON.parseObject(replace);

            return R.ok(jsonObject).put("qa_list",msg);


        } else {
            return R.error();
            // 当msg为空时，可以返回一个默认的ChatResponse实例、空响应或其他错误信息
//            return Mono.just(new ChatResponse("1", "1", "1", 1, 1, true, true, "1", null, "你找到我的bug了", null, null, null, null, null, null, null, null)); // 示例返回一个带有默认提示信息的ChatResponse实例
        }
    }


    @GetMapping("wenxinya")
    public void getfewf(String msg) {

        Mono<ChatResponse> chatResponseMono = ernieBot4Client.chatSingle(msg);

        ChatResponse block = chatResponseMono.block();
        String result = block.getResult();
        System.out.println(result);
    }

    public static void main(String[] args) {

        String msg = "[{\"answer\":\"核心Java：熟悉Java语言的基础，包括OOP（面向对象编程）原则、数据类型、控制流、异常处理等。Java EE (Enterprise Edition)：Java EE为企业级应用提供了一套丰富的API和服务。开发者可能熟悉Servlets、JSPs、EJBs (Enterprise JavaBeans)、JPA (Java Persistence API)、JMS (Java Message Service) 等技术。Spring框架：Spring是Java社区中最流行的框架之一，提供了全面的编程和配置模型。开发者可能使用过Spring Core、Spring MVC、Spring Boot、Spring Data和Spring Security等模块。微服务架构：随着微服务架构的流行，Java开发者可能会使用Spring Cloud、Docker和Kubernetes等工具来构建和管理分布式系统。数据库技术：熟悉SQL和至少一种关系型数据库（如MySQL、PostgreSQL）或NoSQL数据库（如MongoDB、Cassandra）的使用。\",\"question\":\"请您介绍一下自己以及您在Java领域的工作经验，包括您使用过的一些主要的Java框架和技术栈。\"},{\"answer\":\"Java中的垃圾回收（Garbage Collection，GC）是一种自动内存管理机制，它负责回收不再使用的对象所占用的内存。Java虚拟机（JVM）有一个运行时数据区，其中包含堆（Heap）和方法区（Method Area），这些区域用于存储对象实例和类信息。垃圾回收器（Garbage Collector）主要关注堆的内存管理。\",\"question\":\"在Java中，垃圾回收是一个非常重要的概念。您能解释一下Java中的垃圾回收机制以及它是如何工作的吗？同时，您能否举例说明哪些情况下可能导致内存泄漏？\"},{\"answer\":\"线程安全是指在并发编程中，当多个线程同时访问共享资源时，能够保证资源的一致性和完整性，不会出现数据污染或状态异常的现象。简单来说，一个类或代码块是线程安全的，如果它的行为在任何时刻都不会因为其他线程的介入而变得不可预测或不正确。\",\"question\":\"线程安全是指在并发编程中，当多个线程同时访问共享资源时，能够保证资源的一致性和完整性，不会出现数据污染或状态异常的现象。简单来说，一个类或代码块是线程安全的，如果它的行为在任何时刻都不会因为其他线程的介入而变得不可预测或不正确。\"},{\"answer\":\"Java中的异常处理机制是一种用于处理运行时错误的方法，它允许程序在遇到错误时优雅地恢复。异常处理主要依赖于try、catch和finally这三个关键字。\",\"question\":\"请问Java中的异常处理机制是如何工作的？请说明一下try-catch-finally语句块的执行顺序，并谈谈finally块的重要性。同时，您能否给出一些在实际项目中处理异常的最佳实践？\"},{\"answer\":\"Java中的泛型是一种在编译时提供类型安全检查的机制，它允许程序员在类、接口和方法中定义和使用类型参数。泛型的主要作用是提供代码的可重用性和类型安全。\",\"question\":\"在Java中，泛型是一个非常有用的特性。请解释一下泛型的作用以及使用泛型的好处。同时，您能否谈一下Java中的类型擦除以及它在泛型中的应用？\"},{\"answer\":\"Spring Boot旨在简化Spring应用的创建和开发过程。它允许你通过最少的配置来启动和运行一个Spring应用。\",\"question\":\"请问您对Spring框架有多熟悉？能否谈一下Spring框架的核心特性以及您在实际项目中是如何使用Spring框架的？另外，对于Spring Boot和Spring Cloud这两个流行的项目，您有什么了解和使用经验吗？\"}]";
        List<QA> qas = JSON.parseArray(msg, QA.class);


        String aianswer = "\n" +
                "{\n" +
                "  \"total_score\": 85,\n" +
                "  \"question_1\": {\n" +
                "    \"score\": 90,\n" +
                "    \"evaluation\": \"回答者对Java领域的工作经验有深入的了解，熟悉多种Java框架和技术栈，包括Java EE、Spring框架、微服务架构和数据库技术等。回答内容丰富，展示了回答者在Java领域的专业能力和经验。\",\n" +
                "    \"suggested_answer\": \"无需改进，回答已经很完善。\"\n" +
                "  },\n" +
                "  \"question_2\": {\n" +
                "    \"score\": 80,\n" +
                "    \"evaluation\": \"回答者解释了Java中的垃圾回收机制以及它的工作方式，但未提及哪些情况下可能导致内存泄漏的具体例子。虽然回答了问题的一部分，但不够完整。\",\n" +
                "    \"suggested_answer\": \"可以在回答中增加一些导致内存泄漏的具体场景，例如：长时间持有不再需要的对象引用、静态集合类中存储大量对象且未进行清理、数据库连接未正确关闭等。\"\n" +
                "  },\n" +
                "  \"question_3\": {\n" +
                "    \"score\": 90,\n" +
                "    \"evaluation\": \"回答者对线程安全的概念有清晰的理解，能够准确解释线程安全的含义。回答简洁明了，没有冗余信息。\",\n" +
                "    \"suggested_answer\": \"无需改进，回答已经很完善。\"\n" +
                "  },\n" +
                "  \"question_4\": {\n" +
                "    \"score\": 80,\n" +
                "    \"evaluation\": \"回答者解释了Java中的异常处理机制以及try-catch-finally语句块的执行顺序，但未详细谈论finally块的重要性，也未给出实际项目中处理异常的最佳实践。回答略显简略，缺乏一些关键信息。\",\n" +
                "    \"suggested_answer\": \"可以在回答中强调finally块的重要性，例如：无论是否发生异常，finally块中的代码总是会被执行，因此常用于资源清理操作。同时，可以提供一些实际项目中处理异常的最佳实践，如：避免捕获过于广泛的异常类型、记录异常信息并合理处理、在必要时向上抛出异常等。\"\n" +
                "  },\n" +
                "  \"question_5\": {\n" +
                "    \"score\": 80,\n" +
                "    \"evaluation\": \"回答者解释了Java中泛型的作用和使用泛型的好处，但未提及Java中的类型擦除及其在泛型中的应用。回答了一部分问题，但不够全面。\",\n" +
                "    \"suggested_answer\": \"可以在回答中补充关于Java类型擦除的内容，例如：Java中的类型擦除是指在编译后将泛型类型信息删除，只保留原始类型信息。这样做是为了保持与旧版Java代码的兼容性。同时，可以进一步解释类型擦除对泛型的影响和限制。\"\n" +
                "  },\n" +
                "  \"question_6\": {\n" +
                "    \"score\": 80,\n" +
                "    \"evaluation\": \"回答者简要介绍了Spring Boot的作用，但对Spring框架的核心特性以及实际项目中的使用经验未进行详细说明。同时，对于Spring Cloud的了解和使用经验也未给出具体信息。回答略显简略，缺乏一些关键内容。\",\n" +
                "    \"suggested_answer\": \"可以在回答中进一步展开对Spring框架核心特性的解释，例如：依赖注入、面向切面编程等。同时，可以分享一些在实际项目中使用Spring框架的经验，如：如何解决特定问题、提高了开发效率等。另外，对于Spring Cloud的了解和使用经验也可以进行补充，例如：在微服务架构中如何使用Spring Cloud进行服务治理、配置管理等。\"\n" +
                "  }\n" +
                "}\n";

        JSONObject jsonObject = JSON.parseObject(aianswer);
        for (String key : jsonObject.keySet()) {

            if (key.startsWith("question_")) {
                Integer prefix_index = Integer.valueOf(key.replace("question_", "")) - 1;

                JSONObject questionObj = jsonObject.getJSONObject(key);
                questionObj.put("question", qas.get(prefix_index).getQuestion());
                questionObj.put("answer", qas.get(prefix_index).getAnswer());
            }
        }

        System.out.println(jsonObject);


    }

    @GetMapping("/stream/chat")
    public SseEmitter streamChatSingle(String msg) {

        SseEmitter emitter = new SseEmitter();
        if (StrUtil.isNotEmpty(msg)) {
            ernieBot4Client.chatSingleOfStream(msg).subscribe(
                    chatResponse -> {
                        try {
                            emitter.send(SseEmitter.event().data(chatResponse.getResult()));
                        } catch (IOException e) {
                            emitter.completeWithError(e);
                        }
                    },
                    throwable -> {
                        // 错误处理
                        emitter.completeWithError(throwable);
                    },
                    () -> {
                        // 完成时处理（如流结束或资源释放）
                        emitter.complete();
                    }
            );
            //使用client 去请求， response 分段回来，同时使用 sse 分段推送到客户端
        } else {
            // 当msg为空时，可以返回一个默认的ChatResponse实例、空响应或其他错误信息
        }

        return emitter;
    }


    // 流式返回，连续对话（SSE形式）
    @GetMapping(value = "/stream/chats", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter chatSingleSSE(@RequestParam String msg, String userId) {
        String chatUID = "test-user-" + userId;
        SseEmitter emitter = new SseEmitter();

        //使用client 去请求， response 分段回来，同时使用 sse 分段推送到客户端
        ernieBot4Client.chatContOfStream(msg, chatUID).subscribe(response -> {
            try {
                emitter.send(SseEmitter.event().data(response.getResult()));
            } catch (Exception e) {
                emitter.completeWithError(e);
            }
        }, emitter::completeWithError, emitter::complete);
        return emitter;
    }


    @PostMapping("/prompt")
    public Mono<PromptResponse> chatSingle() {

        Map<String, String> map = new HashMap<>();
        map.put("job", "Java工程师");
        map.put("requirement", "爱学习");
        map.put("resume", "喜欢学习");

        ChatPromptRequest promptRequest = new ChatPromptRequest();
        promptRequest.setId("pt-rsdtgpc740zrqn1e"); // interview 那个prompt
        promptRequest.setParamMap(map);
//        PromptRequest promptRequest = ConvertUtils.toPromptRequest(chatPromptRequest);
        Map<String, String> paramMap = promptRequest.getParamMap();
        paramMap.put("id", promptRequest.getId());
        Mono<PromptResponse> promptResponseMono = ChatCore.monoChatGet(
                Constant.PROMPT_URL, promptBotClient.getCustomAccessToken(), paramMap, PromptResponse.class
        );

        promptResponseMono.subscribe(
                // onNext: 当Mono成功时，这个函数会被调用，并传入响应对象
                promptResponse -> {
                    System.out.println("最后得到的Prompt效果》》 " + promptResponse);
                },
                // onError: 当Mono有错误时，这个函数会被调用，并传入异常对象
                error -> {
                    error.printStackTrace();
                    System.out.println("出错了");
                    // 处理错误逻辑...
                },
                // onComplete: 当Mono完成（无论是正常结束还是出错）时，这个函数会被调用
                () -> System.out.println("Chat operation completed")
        );

        return promptResponseMono;

    }

    // 文生图
    @GetMapping("/image")
    public Mono<ImageResponse> chatImage() {
        ImageBaseRequest imageBaseRequest = ImageBaseRequest.builder()
                // 提示词
                .prompt("一个头发中分背带裤的人")
                // 大小
                .size("1024x1024")
                // 反向提示词（不包含什么）
                .negativePrompt("鸡")
                // 生成图片数量（1-4）
                .n(1)
                // 迭代轮次（10-50）
                .steps(20)
                // 采样方式
                .samplerIndex(SamplerType.Euler_A.getValue())
                .userId("1001")
                .build();

        return stableDiffusionXLClient.chatImage(imageBaseRequest);
    }

}
